package dao;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;

public class GenericDAOImpl<T> implements GenericDAO<T> {
	private Class<T> clazz;
	private EntityManager em;

	public GenericDAOImpl(Class<T> clazz) {
		this.clazz = clazz;
		EntityManagerFactory factory = Persistence
				.createEntityManagerFactory("P2PDEVUnit");
		em = factory.createEntityManager();
	}

	public long countAll(final Map params) {

		final StringBuffer queryString = new StringBuffer(
				"SELECT count(o) from ");

		queryString.append(clazz.getSimpleName()).append(" o ");
		queryString.append(this.getQueryClauses(params, null));

		final Query query = this.em.createQuery(queryString.toString());

		return (Long) query.getSingleResult();

	}

	public T get(Serializable id) {
		if (id == null)
			return null;
		return this.em.find(clazz, id);
	}

	public List<T> find(final String queryStr, final Object[] params,
			final int begin, final int max) {
		// TODO Auto-generated method stub
		List<T> ret = null;
		String clazzName = clazz.getName();
		StringBuffer sb = new StringBuffer("select obj from ");
		sb.append(clazzName).append(" obj").append(" where ").append(queryStr);
		Query query = em.createQuery(sb.toString());
		int parameterIndex = 1;
		if (params != null && params.length > 0) {
			for (Object obj : params) {
				query.setParameter(parameterIndex++, obj);
			}
		}
		if (begin >= 0 && max > 0) {
			query.setFirstResult(begin);
			query.setMaxResults(max);
		}
		ret = query.getResultList();
		if (ret != null && ret.size() >= 0) {
			return ret;
		} else {
			return new ArrayList<T>();
		}
	}

	public void remove(Serializable id) {
		if (id == null)
			throw new java.lang.IllegalArgumentException("id值不能为空!");
		T object = this.get(id);
		if (object != null) {
			this.em.remove(this.em.getReference(clazz, id));
		}
	}

	public void save(T instance) {
		this.em.persist(instance);
	}

	public T getBy(final String propertyName, final Object value) {
		if (propertyName == null || "".equals(propertyName) || value == null)
			throw new IllegalArgumentException("调用参数不正确，属性名称及值均不能为空!");
		// TODO Auto-generated method stub
		List<T> ret = null;
		String clazzName = clazz.getName();
		StringBuffer sb = new StringBuffer("select obj from ");
		sb.append(clazzName).append(" obj");
		Query query = null;
		if (propertyName != null && value != null) {
			sb.append(" where obj.").append(propertyName).append(" = :value");
			query = em.createQuery(sb.toString()).setParameter("value", value);
		} else {
			query = em.createQuery(sb.toString());
		}
		ret = query.getResultList();
		if (ret != null && ret.size() == 1) {
			return ret.get(0);
		} else if (ret != null && ret.size() > 1) {
			throw new java.lang.IllegalStateException(
					"worning  --more than one object find!!");
		} else {
			return null;
		}
	}

	public void update(T instance) {
		this.em.merge(instance);
	}
	
	public List executeNativeNamedQuery(final String nnq) {
		Object ret = null;

		Query query = em.createNativeQuery(nnq);
		ret = query.getResultList();
		return (List) ret;
	}

	private String getQueryClauses(final Map<String, Object> params,
			final Map<String, Object> orderParams) {
		final StringBuffer queryString = new StringBuffer();
		if ((params != null) && !params.isEmpty()) {
			queryString.append(" where ");
			for (final Iterator<Map.Entry<String, Object>> it = params
					.entrySet().iterator(); it.hasNext();) {
				final Map.Entry<String, Object> entry = it.next();
				if (entry.getValue() instanceof Boolean) {
					queryString.append(entry.getKey()).append(" is ")
							.append(entry.getValue()).append(" ");
				} else {
					if (entry.getValue() instanceof Number) {
						queryString.append(entry.getKey()).append(" = ")
								.append(entry.getValue());
					} else {
						// string equality
						queryString.append(entry.getKey()).append(" = '")
								.append(entry.getValue()).append("'");
					}
				}
				if (it.hasNext()) {
					queryString.append(" and ");
				}
			}
		}
		if ((orderParams != null) && !orderParams.isEmpty()) {
			queryString.append(" order by ");
			for (final Iterator<Map.Entry<String, Object>> it = orderParams
					.entrySet().iterator(); it.hasNext();) {
				final Map.Entry<String, Object> entry = it.next();
				queryString.append(entry.getKey()).append(" ");
				if (entry.getValue() != null) {
					queryString.append(entry.getValue());
				}
				if (it.hasNext()) {
					queryString.append(", ");
				}
			}
		}
		return queryString.toString();
	}
	public void setClazzType(Class clazz) {
		this.clazz = clazz;
	}

	public Class getClassType() {
		return this.clazz;
	}
	
}